package model.rotations;

import model.cubos.Adesivo;
import model.cubos.CuboMagico;
import model.cubos.CuboMagico3x3x3;
import model.matrizes.MatrizBidimensional;

/**
 * Esta classe possui as possíveis rotações do {@link CuboMagico}.
 * 
 * @author Joeffison Silverio de Andrade, 21011853, joeffisonsa@gmail.com
 * @version 1.0
 * @since 12/11/11 08:28
 */
public class RotationsImpl implements Rotations {

	@Override
	public void U(CuboMagico cubo) {
		Adesivo[][][] cube = cubo.getCubo();
		
		// Todos os cubos tem apenas 4 cores.
		Adesivo[] linha_0 = cube[0][0];
		Adesivo[] linha_1 = cube[1][0];
		Adesivo[] linha_2 = cube[2][0];
		Adesivo[] linha_3 = cube[3][0];
		//Adesivo[][] linhas_do_topo = cube[4]; // É o próprio topo.
		
		
		/* Trocando as linhas. */
		cube[0][0] = linha_1;
		cube[1][0] = linha_2;
		cube[2][0] = linha_3;
		cube[3][0] = linha_0;
		
		MatrizBidimensional.transposta(cube[4]); // Finalmente aplicando conceitos que pensamos não ter aplicações... xP
		MatrizBidimensional.espelharColunas(cube[4]);
		
	}

	@Override
	public void U_(CuboMagico cubo) {
		U(cubo);
		U(cubo);
		U(cubo);
	}

	@Override
	public void U2(CuboMagico cubo) {
		U(cubo);
		U(cubo);
	}

	@Override
	public void D(CuboMagico cubo) {
		Adesivo[][][] cube = cubo.getCubo();
		
		// Todos os cubos tem apenas 4 cores.
		Adesivo[] linha_0 = cube[0][cube[0].length-1]; // Últimas linhas do cubo.
		Adesivo[] linha_1 = cube[1][cube[0].length-1];
		Adesivo[] linha_2 = cube[2][cube[0].length-1];
		Adesivo[] linha_3 = cube[3][cube[0].length-1];
		
		//Adesivo[][] linhas_do_topo = cube[4]; // É o próprio topo.
		
		
		/* Trocando as linhas. */
		cube[0][cube[0].length-1] = linha_3;
		cube[1][cube[0].length-1] = linha_0;
		cube[2][cube[0].length-1] = linha_1;
		cube[3][cube[0].length-1] = linha_2;
		
		MatrizBidimensional.transposta(cube[5]);
		MatrizBidimensional.espelharColunas(cube[5]);
	}

	@Override
	public void D_(CuboMagico cubo) {
		D(cubo);
		D(cubo);
		D(cubo);
	}

	@Override
	public void D2(CuboMagico cubo) {
		D(cubo);
		D(cubo);
	}

	@Override
	public void F(CuboMagico cubo) {
		Adesivo[][][] cube = cubo.getCubo();
		int dim = cube[0].length;
		int[] interacaoCoresColunas = {1, 3};
		Adesivo[][] colunas = new Adesivo[2][dim];
		Adesivo[][] linhas = new Adesivo[2][dim];
		for (int i = 0; i<interacaoCoresColunas.length; i++) {
			for (int j = 0; j<dim; j++) {
				colunas[i][j] = cube[interacaoCoresColunas[i]][j][(i==0? 0:2)];
			}
		}
		linhas[0] = cube[4][2];
		linhas[1] = cube[5][0];
		
		cube[1][0][0] = linhas[0][0];
		cube[1][1][0] = linhas[0][1];
		cube[1][2][0] = linhas[0][2];
		
		cube[3][0][2] = linhas[1][0];
		cube[3][1][2] = linhas[1][1];
		cube[3][2][2] = linhas[1][2];
		
		cube[4][2][0] = colunas[1][2];
		cube[4][2][1] = colunas[1][1];
		cube[4][2][2] = colunas[1][0];
		
		cube[5][0][0] = colunas[0][2];
		cube[5][0][1] = colunas[0][1];
		cube[5][0][2] = colunas[0][0];
		
		MatrizBidimensional.transposta(cube[0]);
		MatrizBidimensional.espelharColunas(cube[0]);
	}

	@Override
	public void F_(CuboMagico cubo) {
		F(cubo);
		F(cubo);
		F(cubo);
	}

	@Override
	public void F2(CuboMagico cubo) {
		F(cubo);
		F(cubo);
	}

	@Override
	public void B(CuboMagico cubo) {
		Adesivo[][][] cube = cubo.getCubo();
		int dim = cube[0].length;
		int[] interacaoCoresColunas = {1, 3};
		Adesivo[][] colunas = new Adesivo[2][dim];
		Adesivo[][] linhas = new Adesivo[2][dim];
		for (int i = 0; i<interacaoCoresColunas.length; i++) {
			for (int j = 0; j<dim; j++) {
				colunas[i][j] = cube[interacaoCoresColunas[i]][j][(i==0? 2:0)];
			}
		}
		linhas[0] = cube[4][0];
		linhas[1] = cube[5][2];
		
		cube[1][0][2] = linhas[1][2];
		cube[1][1][2] = linhas[1][1];
		cube[1][2][2] = linhas[1][0];
		
		cube[3][0][0] = linhas[0][2];
		cube[3][1][0] = linhas[0][1];
		cube[3][2][0] = linhas[0][0];
		
		cube[4][0] = colunas[0];
		
		cube[5][2] = colunas[1];
		
		MatrizBidimensional.transposta(cube[2]);
		MatrizBidimensional.espelharColunas(cube[2]);
	}

	@Override
	public void B_(CuboMagico cubo) {
		B(cubo);
		B(cubo);
		B(cubo);
	}

	@Override
	public void B2(CuboMagico cubo) {
		B(cubo);
		B(cubo);
	}

	@Override
	public void R(CuboMagico cubo) {
		Adesivo[][][] cube = cubo.getCubo();
		int dim = cube[0].length;
		int[] interacaoCores = {0, /*2,*/ 4, 5};
		Adesivo[][] colunas = new Adesivo[4][dim];
		for (int i = 0; i<interacaoCores.length; i++) {
			for (int j = 0; j<dim; j++) {
				colunas[i][j] = cube[interacaoCores[i]][j][dim-1];
			}
		}
		for (int j = 0; j<dim; j++) {
			colunas[colunas.length-1][j] = cube[2][j][0];
		}
		
		cube[0][0][2] = colunas[2][0];
		cube[0][1][2] = colunas[2][1];
		cube[0][2][2] = colunas[2][2];
		
		cube[4][0][2] = colunas[0][0];
		cube[4][1][2] = colunas[0][1];
		cube[4][2][2] = colunas[0][2];
		
		cube[5][0][2] = colunas[3][2];
		cube[5][1][2] = colunas[3][1];
		cube[5][2][2] = colunas[3][0];
		
		cube[2][0][0] = colunas[1][2];
		cube[2][1][0] = colunas[1][1];
		cube[2][2][0] = colunas[1][0];
		
		MatrizBidimensional.transposta(cube[1]);
		MatrizBidimensional.espelharColunas(cube[1]);
	}

	@Override
	public void R_(CuboMagico cubo) {
		R(cubo);
		R(cubo);
		R(cubo);
	}

	@Override
	public void R2(CuboMagico cubo) {
		R(cubo);
		R(cubo);
	}

	@Override
	public void L(CuboMagico cubo) {
		Adesivo[][][] cube = cubo.getCubo();
		int dim = cube[0].length;
		int[] interacaoCores = {0, /*2,*/ 4, 5};
		Adesivo[][] colunas = new Adesivo[4][dim];
		for (int i = 0; i<interacaoCores.length; i++) {
			for (int j = 0; j<dim; j++) {
				colunas[i][j] = cube[interacaoCores[i]][j][0];
			}
		}
		for (int j = 0; j<dim; j++) {
			colunas[colunas.length-1][j] = cube[2][j][dim-1];
		}
		
		cube[0][0][0] = colunas[1][0];
		cube[0][1][0] = colunas[1][1];
		cube[0][2][0] = colunas[1][2];
		
		cube[5][0][0] = colunas[0][0];
		cube[5][1][0] = colunas[0][1];
		cube[5][2][0] = colunas[0][2];
		
		cube[4][0][0] = colunas[3][2];
		cube[4][1][0] = colunas[3][1];
		cube[4][2][0] = colunas[3][0];
		
		cube[2][0][2] = colunas[2][2];
		cube[2][1][2] = colunas[2][1];
		cube[2][2][2] = colunas[2][0];
		
		MatrizBidimensional.transposta(cube[3]);
		MatrizBidimensional.espelharColunas(cube[3]);
	}

	@Override
	public void L_(CuboMagico cubo) {
		L(cubo);
		L(cubo);
		L(cubo);
	}

	@Override
	public void L2(CuboMagico cubo) {
		L(cubo);
		L(cubo);
	}

	@Override
	public void executa(CuboMagico cubo, String[] operacoes) {
		for (String oper : operacoes) {
			if (oper.equals("U")) {
				U(cubo);
			} else if (oper.equals("U_")) {
				U_(cubo);
			} else if (oper.equals("U2")) {
				U2(cubo);
			} else if (oper.equals("D")) {
				D(cubo);
			} else if (oper.equals("D_")) {
				D_(cubo);
			} else if (oper.equals("D2")) {
				D2(cubo);
			} else if (oper.equals("F")) {
				F(cubo);
			} else if (oper.equals("F_")) {
				F_(cubo);
			} else if (oper.equals("F2")) {
				F2(cubo);
			} else if (oper.equals("B")) {
				B(cubo);
			} else if (oper.equals("B_")) {
				B_(cubo);
			} else if (oper.equals("B2")) {
				B2(cubo);
			} else if (oper.equals("R")) {
				R(cubo);
			} else if (oper.equals("R_")) {
				R_(cubo);
			} else if (oper.equals("R2")) {
				R2(cubo);
			} else if (oper.equals("L")) {
				L(cubo);
			} else if (oper.equals("L_")) {
				L_(cubo);
			} else if (oper.equals("L2")) {
				L2(cubo);
			} else if (oper.equals("Z")) {
				Z(cubo);
			} else if (oper.equals("Z_")) {
				Z_(cubo);
			} else if (oper.equals("Z2")) {
				Z2(cubo);
			} else {}
		}
	}

	public void Z(CuboMagico cubo) {
		Adesivo[][][] cube = cubo.getCubo();
		int dim = cube[0].length;
		int[] interacaoCores = {1, 3/*, 4, 5*/};
		Adesivo[][] colunas = new Adesivo[2][dim];
		Adesivo[][] linhas = new Adesivo[2][dim];
		for (int i = 0; i<interacaoCores.length; i++) {
			for (int j = 0; j<dim; j++) {
				colunas[i][j] = cube[interacaoCores[i]][j][1];
			}
		}
		
		linhas[0] = cube[4][1];
		linhas[1] = cube[5][1];
		
		cube[1][0][1] = linhas[1][2];
		cube[1][1][1] = linhas[1][1];
		cube[1][2][1] = linhas[1][0];
		
		cube[3][0][1] = linhas[0][2];
		cube[3][1][1] = linhas[0][1];
		cube[3][2][1] = linhas[0][0];
		
		cube[4][1] = colunas[0];
		
		cube[5][1] = colunas[1];
		
		F_(cubo);
		B(cubo);
	}
	
	public void Z_(CuboMagico cubo) {
		Z(cubo);
		Z(cubo);
		Z(cubo);
	}
	
	public void Z2(CuboMagico cubo) {
		Z(cubo);
		Z(cubo);
	}

	public void X(CuboMagico cubo) {
		Adesivo[][][] cube = cubo.getCubo();
		int dim = cube[0].length;
		int[] interacaoCores = {0, 2, 4, 5};
		Adesivo[][] colunas = new Adesivo[4][dim];
		for (int i = 0; i<interacaoCores.length; i++) {
			for (int j = 0; j<dim; j++) {
				colunas[i][j] = cube[interacaoCores[i]][j][1];
			}
		}
		
		cube[0][0][1] = colunas[3][0];
		cube[0][1][1] = colunas[3][1];
		cube[0][2][1] = colunas[3][2];
		
		cube[2][0][1] = colunas[2][2];
		cube[2][1][1] = colunas[2][1];
		cube[2][2][1] = colunas[2][0];
		
		cube[4][0][1] = colunas[0][0];
		cube[4][1][1] = colunas[0][1];
		cube[4][2][1] = colunas[0][2];
		
		cube[5][0][1] = colunas[1][2];
		cube[5][1][1] = colunas[1][1];
		cube[5][2][1] = colunas[1][0];
		
		L_(cubo);
		R(cubo);
	}
	
	public void X_(CuboMagico cubo) {
		X(cubo);
		X(cubo);
		X(cubo);
	}
	
	public void X2(CuboMagico cubo) {
		X(cubo);
		X(cubo);
	}

	public void Y(CuboMagico cubo) {
		E_(cubo);
		D_(cubo);
		U(cubo);
	}

	public void E_(CuboMagico cubo) {
		Adesivo[][][] cube = cubo.getCubo();
		int dim = cube[0].length;
		Adesivo[][] linhas = new Adesivo[4][dim];
		for (int i = 0; i<4; i++) {
			linhas[i] = cube[i][1];
		}
		
		cube[0][1] = linhas[1];
		cube[1][1] = linhas[2];
		cube[2][1] = linhas[3];
		cube[3][1] = linhas[0];
	}
	
	public void E(CuboMagico cubo) {
		E_(cubo);
		E_(cubo);
		E_(cubo);
	}
	
	public void E2(CuboMagico cubo) {
		E_(cubo);
		E_(cubo);
	}
	
	public void Y_(CuboMagico cubo) {
		Y(cubo);
		Y(cubo);
		Y(cubo);
	}
	
	public void Y2(CuboMagico cubo) {
		Y(cubo);
		Y(cubo);
	}

	
	
	
}
